package com.itgacl.magic4j.libcommon.util;

import com.alibaba.fastjson.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;

/**
 * 字符串工具类
 *
 * @author JackieLiu
 */
public class StringUtil {
    private StringUtil() {
    }


    /**
     * 字符串拼接
     * 首，尾，都将会没有分隔符，分隔符，只在给定的{@code args}字符间存在。
     * <p>
     * 特点：
     * 1、如果传入的可变参数 {@code args} 为空，则直接返回空字符串。
     * 2、如果传入的可变参数 {@code args} 中存在 null 或者 empty 的参数，则不对该参数进行拼接
     *
     * @param delimiter 分隔符
     * @param args      被拼接的字符数组
     * @return 拼接好的字符
     */
    public static String strAppend(String delimiter, Object... args) {
        if (null == args || 0 == args.length) {
            return "";
        }

        //开始拼接
        StringBuilder builder = new StringBuilder();
        for (Object o : args) {
            //过滤无效字符串
            if (null == o || o.toString().isEmpty()) {
                continue;
            }
            builder.append(o).append(delimiter);
        }

        //拼接完成后，看下是否长度为0，为0直接返回空字符串，因为强硬操作截取函数会报出下标越界异常。
        if (0 == builder.length()) {
            return "";
        }

        //去掉最后一个delimiter
        //含头不含尾
        return builder.substring(0, builder.length() - 1);
    }


    /**
     * 对 {@link #strAppend(String, Object...)}的增强扩展
     * 传入的参数有时的确是形形色色，如果都提前单独处理，太繁琐，且浪费空间，指针也便于维护。
     * 无异于提高了空间复杂度和事件复杂度，所以，单独扩展增强一个出来。
     *
     * @param delimiter 拼接的分隔符
     * @param args      增强型参数
     * @return 拼接好的字符
     */
    public static String strAppendExpand(String delimiter, Object[]... args) {
        if (null == args || 0 == args.length) {
            return "";
        }

        StringBuilder builder = new StringBuilder();
        String s = "";
        for (Object[] arr : args) {
            s = strAppend(delimiter, arr);
            //过滤无效字符串
            if (null == s || s.isEmpty()) {
                continue;
            }
            builder.append(s).append(delimiter);
        }

        //拼接完成后，看下是否长度为0，为0直接返回空字符串，因为强硬操作截取函数会报出下标越界异常。
        if (0 == builder.length()) {
            return "";
        }

        //去掉最后一个delimiter
        //含头不含尾
        return builder.substring(0, builder.length() - 1);
    }


    /**
     * 将给定的 {@code msg} 依据给定的 “模板” {@code template} 格式化一个长字符串并返回
     *
     * @param template 需要格式化字符串信息的 “模板”
     * @param msg      需要被格式化字符串中每个字段对应的 value值
     * @return 一个经过格式化的长字符串信息
     */
    public static String formatMsg(String template, Object... msg) {
        // 获取信息的字段
        String[] elements = template.split("\\{\\}");

        // 将获取到的每个字段赋予 value 并拼接成一个长字符串返回
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < msg.length; i++) {
            stringBuilder.append(elements[i]).append(msg[i]);
        }

        // 判断模板 template 末尾是否还存在信息,存在则将其拼接
        if (elements.length > msg.length) {
            stringBuilder.append(elements[elements.length - 1]);
        }

        return stringBuilder.toString();
    }


    /**
     * 获取json
     *
     * @return json
     */
    public static String toJson(String key, Object value) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(key, value);
        return jsonObject.toJSONString();
    }


    /**
     * 判定字符串是否为空
     *
     * @param str 字符串
     * @return null、empty 返回true，反之亦然。
     */
    public static boolean isNothing(String str) {
        return null == str || str.isEmpty();
    }


    /**
     * 字符串判断不为空
     *
     * @param str 字符串
     * @return 不为空返回true，反之false
     */
    public static boolean isNotNothing(String str) {
        return null != str && !str.isEmpty();
    }

    /**
     * 字符串判断不为空
     *
     * @param strArgs 字符串数组
     * @return 不为空返回true，反之false
     */
    public static boolean isNotNothing(String... strArgs) {
        for (String str : strArgs) {
            if (isNothing(str)) {
                return false;
            }
        }
        return true;
    }


    /**
     * 判定给定的字符串数组中，是否存在空字符串。
     *
     * @param values 字符串数组
     * @return 存在 null、empty 返回true，反之亦然。
     */
    public static boolean containsEmpty(String... values) {
        if (null == values || 0 == values.length) {
            return true;
        }

        for (String ele : values) {
            if (isNothing(ele)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 包含与比较关键字相似的元素，则返回true，反之亦然。
     *
     * @param comparator 模糊比较的关键字
     * @param elements   被比较的元素集合
     * @return 比较结果
     */
    public static boolean like(Object comparator, Object... elements) {
        //先确定比较者，不是空值。如果比较者是控制，则直接返回false。
        if (null == comparator || comparator.toString().isEmpty()) {
            return false;
        }

        //开始使用比较者，比较元素内容，包含一个相似的，则返回true。
        String c = comparator.toString();
        String e = "";
        for (Object ele : elements) {
            //如果被比较的元素为空值，则直接跳过，进入下一个元素的比较。
            if (null == ele || ele.toString().isEmpty()) {
                continue;
            }
            e = ele.toString();
            //比较，相似，则返回true。
            if (e.equals(c) || e.contains(c)) {
                return true;
            }
        }

        //如果都能执行到这里，说明与比较者相似的元素一个也没有，返回false。
        return false;
    }


    /**
     * 字符串转字节数组
     * 特性：如果字符串为空，会返回空数组。
     *
     * @param str 字符串
     * @return 字节数组
     */
    public static byte[] getBytes(String str) {
        //空，则返回空数组
        if (null == str || str.isEmpty()) {
            return new byte[0];
        }
        return str.getBytes(StandardCharsets.UTF_8);
    }


    /**
     * 中文字符验证
     */
    private static final Pattern CHINESE_CHARACTER_PATTERN = Pattern.compile("[\u4e00-\u9fa5]");
    /**
     * 中文标点符号验证
     */
    private static final Pattern CHINESE_PUNCTUATION_PATTERN = Pattern.compile("[\uFF01]|[\uFF0C-\uFF0E]|[\uFF1A-\uFF1B]|[\uFF1F]|[\uFF08-\uFF09]|[\u3001-\u3002]|[\u3010-\u3011]|[\u201C-\u201D]|[\u2013-\u2014]|[\u2018-\u2019]|[\u2026]|[\u3008-\u300F]|[\u3014-\u3015]");

    /**
     * 判断字符是否是中文，能校验是否为中文标点符号
     *
     * @param c 字符
     * @return 是汉字返回true, 反之返回false
     */
    public static boolean isChinese(char c) {
        return CHINESE_CHARACTER_PATTERN.matcher(String.valueOf(c)).find() || CHINESE_PUNCTUATION_PATTERN.matcher(String.valueOf(c)).find();
    }


    /**
     * 统计占位数量
     * [0] = 全角占位符数量
     * [1] = 半角占位符数量
     *
     * @param v 字符串
     * @return 占位数量
     */
    public static int[] countPlaceholder(String v) {
        int fullAngle = 0;
        int halfAngle = 0;
        for (char c : v.toCharArray()) {
            if (isChinese(c)) {
                fullAngle++;
            } else {
                halfAngle++;
            }
        }
        return new int[]{fullAngle, halfAngle};
    }


    /**
     * 生成指定长度的占位符字符串，半角占位符。
     *
     * @param len 长度
     * @return 字符串
     */
    public static String halfAngleBlank(int len) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.append(" ");
        }
        return builder.toString();
    }


    /**
     * 生成指定长度的占位符字符串，全角占位符。
     *
     * @param len 长度
     * @return 字符串
     */
    public static String fullAngleBlank(int len) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.append("　");
        }
        return builder.toString();
    }


    /**
     * 右对齐
     *
     * @param v   值
     * @param len 对齐长度
     * @return 对齐输出
     */
    public static String rightAlign(String v, int len) {
        return halfAngleBlank(len - v.length()) + v;
    }


    /**
     * 左对齐
     *
     * @param v   值
     * @param len 对齐长度
     * @return 对齐输出
     */
    public static String leftAlign(String v, int len) {
        return v + halfAngleBlank(len - v.length());
    }


    /**
     * 中文左对齐
     *
     * @param v   值
     * @param len 对齐长度
     * @return 对齐输出
     */
    public static String chineseLeftAlign(String v, int len) {
        int[] holder = countPlaceholder(v);
        return v + halfAngleBlank(len - (holder[0] * 2 + holder[1]));
    }


    /**
     * 中文右对齐
     *
     * @param v   值
     * @param len 对齐长度
     * @return 对齐输出
     */
    public static String chineseRightAlign(String v, int len) {
        int[] holder = countPlaceholder(v);
        return halfAngleBlank(len - (holder[0] * 2 + holder[1])) + v;
    }


}
